线程池
关于参数的描述
1 | /* |
- corePoolSize 线程的核心线程数,核心线程是会保持在线程池中,即使核心线程处于空闲状态,除非allowCoreThreadTimeOut被设置。
- maximumPoolSize: 指的是线程池中允许的最大的线程数
- keepAliveTime: 当线程数大于核心线程数时,多余的空闲线程等待任务的超时时间为keepAliveTime,超时后空闲线程将会被终止
- unit: keepAliveTime的时间单位
- workQueue:线程池的任务队列,这个队列是阻塞式队列,任务通过execute提交。
- threadFactor: 用于创建线程池中线程的工厂类
- handler:饱和策略
线程池任务处理过程
当通过execute提交新任务到线程池中,线程池会做如下操作:
- 如果线程池中正在运行的线程小于corePoolSize,则创建一个新的线程来执行任务。否则,执行步骤2
- 判断线程工作队列workQueue是否已经满,如果工作队列没有满,则将新提交的任务存储在工作队列中等待。否则执行步骤3
- 判断线程池中正在运行的线程数是否小于maximumPoolSize,如果小于,则创建线程运行这个任务,否则执行步骤4
- 这时候线程池的工作队列已满,正在运行的线程数已达到maximumPoolSize指定的值,该任务交给饱和策略处理。
当创建的线程处于空闲状态时,如果超过keepAliveTime的时间,线程池会判断当前运行的线程是否大于coorPoolSize,如果是,那么线程被终止掉。所有线程池的任务完成后,它最终会收缩到coorPoolSize的大小。
这个过程说明,并不是先加入任务就一定会先执行。假设队列大小为 4,corePoolSize为2,maximumPoolSize为6,那么当加入15个任务时,执行的顺序类似这样:首先执行任务 1、2,然后任务3~6被放入队列。这时候队列满了,任务7、8、9、10 会被马上执行,而任务 11~15 则会抛出异常。最终顺序是:1、2、7、8、9、10、3、4、5、6。当然这个过程是针对指定大小的ArrayBlockingQueue
常用线程池
Java通过Executors提供四种线程池,分别为:
- newCachedThreadPool()
1 | public static ExecutorService newCachedThreadPool() { |
创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒处于等待任务到来)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池的最大值是Integer的最大值(2^31-1)。
- newFixedThreadPool(nThreads)
1 | public static ExecutorService newFixedThreadPool(int nThreads) { |
创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,在提交新任务,任务将会进入等待队列中等待。如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
- newSingleThreadExecutor
1 | public static ExecutorService newSingleThreadExecutor() { |
创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
- newScheduledThreadPool(int corePoolSize)
1 | public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { |
创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。